/**
 * 自动备份服务
 * EndoSight-UC 医疗AI系统 - 数据库安全紧急修复
 *
 * 提供自动化、加密的数据库备份服务
 */

import fs from 'fs';
import path from 'path';
import crypto from 'crypto';
import { fileURLToPath } from 'url';
import { createSecureLogger } from '../utils/secureLoggingConfig.js';
import { createSimpleEncryptedDatabase } from '../config/simpleEncryptedDatabase.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 安全日志记录器
const logger = createSecureLogger({
  service: 'BackupService',
  logLevel: 'info'
});

// 备份配置
const backupConfig = {
  // 备份目录
  backupDir: process.env.BACKUP_DIR || path.join(__dirname, '../../backups'),
  // 保留策略
  retention: {
    daily: 7,      // 保留7天的日备份
    weekly: 4,     // 保留4周的周备份
    monthly: 12    // 保留12个月的月备份
  },
  // 加密配置
  encryption: {
    algorithm: 'aes-256-cbc',
    keyLength: 32,
    ivLength: 16
  }
};

/**
 * 确保备份目录存在且权限正确
 */
const ensureBackupDirectory = () => {
  try {
    if (!fs.existsSync(backupConfig.backupDir)) {
      fs.mkdirSync(backupConfig.backupDir, { recursive: true });
      logger.info('Backup directory created', { path: backupConfig.backupDir });
    }

    // 设置目录权限（仅所有者可读写执行）
    fs.chmodSync(backupConfig.backupDir, 0o700);

    return true;
  } catch (error) {
    logger.logError(error, { operation: 'ensure_backup_directory' });
    return false;
  }
};

/**
 * 生成备份文件名
 */
const generateBackupFileName = (type = 'daily') => {
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
  return `endo_sight_uc_${type}_${timestamp}.backup`;
};

/**
 * 加密备份数据
 */
const encryptBackupData = (data, encryptionKey) => {
  try {
    const iv = crypto.randomBytes(backupConfig.encryption.ivLength);
    const cipher = crypto.createCipher(backupConfig.encryption.algorithm, encryptionKey);

    let encrypted = cipher.update(JSON.stringify(data), 'utf8', 'hex');
    encrypted += cipher.final('hex');

    return {
      algorithm: backupConfig.encryption.algorithm,
      iv: iv.toString('hex'),
      data: encrypted,
      timestamp: new Date().toISOString(),
      version: '1.0'
    };
  } catch (error) {
    logger.logError(error, { operation: 'encrypt_backup_data' });
    throw error;
  }
};

/**
 * 解密备份数据
 */
const decryptBackupData = (encryptedData, encryptionKey) => {
  try {
    const decipher = crypto.createDecipher(backupConfig.encryption.algorithm, encryptionKey);
    decipher.setAAD(Buffer.from(encryptedData.iv, 'hex'));

    let decrypted = decipher.update(encryptedData.data, 'hex', 'utf8');
    decrypted += decipher.final('utf8');

    return JSON.parse(decrypted);
  } catch (error) {
    logger.logError(error, { operation: 'decrypt_backup_data' });
    throw new Error('Backup decryption failed: invalid key or corrupted data');
  }
};

/**
 * 获取加密密钥
 */
const getEncryptionKey = () => {
  const key = process.env.BACKUP_ENCRYPTION_KEY || process.env.DB_ENCRYPTION_KEY;
  if (!key) {
    throw new Error('BACKUP_ENCRYPTION_KEY or DB_ENCRYPTION_KEY environment variable is required');
  }
  return Buffer.from(key, 'hex').slice(0, backupConfig.encryption.keyLength);
};

/**
 * 执行数据库备份
 */
const performBackup = async (type = 'daily') => {
  try {
    logger.info('Starting database backup', { type });

    // 确保备份目录存在
    if (!ensureBackupDirectory()) {
      throw new Error('Failed to create backup directory');
    }

    // 获取加密密钥
    const encryptionKey = getEncryptionKey();

    // 连接数据库
    const dbPath = path.join(__dirname, '../../data/endo_sight_uc.db');
    const encryptedDb = await createSimpleEncryptedDatabase(dbPath);

    // 备份所有表的数据
    const backupData = {
      metadata: {
        version: '1.0',
        timestamp: new Date().toISOString(),
        type: type,
        system: 'EndoSight-UC Medical AI',
        description: 'Encrypted database backup'
      },
      tables: {}
    };

    // 备份医生表
    try {
      const doctors = await encryptedDb.all('SELECT * FROM doctors', [], {
        decryptFields: ['password', 'email', 'license_number'],
        table: 'doctors'
      });
      backupData.tables.doctors = doctors;
      logger.info('Doctors table backed up', { count: doctors.length });
    } catch (error) {
      logger.warn('Failed to backup doctors table', { error: error.message });
    }

    // 备份患者表（如果存在）
    try {
      const patients = await encryptedDb.all('SELECT * FROM patients', [], {
        decryptFields: ['name', 'id_card', 'phone', 'email', 'address'],
        table: 'patients'
      });
      backupData.tables.patients = patients;
      logger.info('Patients table backed up', { count: patients.length });
    } catch (error) {
      logger.info('Patients table not found or empty', { error: error.message });
    }

    // 备份评分记录表
    try {
      const scoringRecords = await encryptedDb.all('SELECT * FROM scoring_records', [], {
        decryptFields: ['doctor_notes', 'patient_complaints'],
        table: 'scoring_records'
      });
      backupData.tables.scoring_records = scoringRecords;
      logger.info('Scoring records table backed up', { count: scoringRecords.length });
    } catch (error) {
      logger.warn('Failed to backup scoring records table', { error: error.message });
    }

    // 备份系统配置表
    try {
      const systemConfigs = await encryptedDb.all('SELECT * FROM system_configs');
      backupData.tables.system_configs = systemConfigs;
      logger.info('System configs table backed up', { count: systemConfigs.length });
    } catch (error) {
      logger.info('System configs table not found', { error: error.message });
    }

    // 关闭数据库连接
    await encryptedDb.close();

    // 加密备份数据
    const encryptedBackup = encryptBackupData(backupData, encryptionKey);

    // 生成备份文件名
    const backupFileName = generateBackupFileName(type);
    const backupFilePath = path.join(backupConfig.backupDir, backupFileName);

    // 写入加密备份文件
    fs.writeFileSync(backupFilePath, JSON.stringify(encryptedBackup, null, 2));

    // 设置备份文件权限（仅所有者可读写）
    fs.chmodSync(backupFilePath, 0o600);

    // 生成备份校验和
    const fileHash = crypto.createHash('sha256').update(fs.readFileSync(backupFilePath)).digest('hex');

    const backupResult = {
      success: true,
      type: type,
      fileName: backupFileName,
      filePath: backupFilePath,
      fileSize: fs.statSync(backupFilePath).size,
      fileHash: fileHash,
      timestamp: new Date().toISOString(),
      tables: Object.keys(backupData.tables),
      recordCounts: Object.fromEntries(
        Object.entries(backupData.tables).map(([table, records]) => [table, records.length])
      )
    };

    logger.info('Database backup completed successfully', backupResult);

    // 清理过期备份
    await cleanupOldBackups(type);

    return backupResult;

  } catch (error) {
    logger.logError(error, { operation: 'perform_backup', type });
    throw error;
  }
};

/**
 * 清理过期备份
 */
const cleanupOldBackups = async (type) => {
  try {
    const retentionDays = backupConfig.retention[type];
    if (!retentionDays) return;

    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - retentionDays);

    const backupFiles = fs.readdirSync(backupConfig.backupDir)
      .filter(file => file.endsWith('.backup') && file.includes(`_${type}_`));

    let deletedCount = 0;
    for (const file of backupFiles) {
      const filePath = path.join(backupConfig.backupDir, file);
      const stats = fs.statSync(filePath);

      if (stats.mtime < cutoffDate) {
        fs.unlinkSync(filePath);
        deletedCount++;
        logger.info('Deleted old backup', { file, age: Math.floor((Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60 * 24)) });
      }
    }

    if (deletedCount > 0) {
      logger.info('Backup cleanup completed', {
        type,
        deletedCount,
        remainingCount: backupFiles.length - deletedCount
      });
    }

  } catch (error) {
    logger.logError(error, { operation: 'cleanup_old_backups', type });
  }
};

/**
 * 恢复数据库备份
 */
const restoreBackup = async (backupFileName) => {
  try {
    logger.info('Starting database restore', { backupFileName });

    const backupFilePath = path.join(backupConfig.backupDir, backupFileName);

    if (!fs.existsSync(backupFilePath)) {
      throw new Error(`Backup file not found: ${backupFileName}`);
    }

    // 读取并解密备份文件
    const encryptedBackup = JSON.parse(fs.readFileSync(backupFilePath, 'utf8'));
    const encryptionKey = getEncryptionKey();
    const backupData = decryptBackupData(encryptedBackup, encryptionKey);

    logger.info('Backup decrypted successfully', {
      version: backupData.metadata.version,
      timestamp: backupData.metadata.timestamp,
      tables: Object.keys(backupData.tables)
    });

    // 连接数据库
    const dbPath = path.join(__dirname, '../../data/endo_sight_uc.db');
    const encryptedDb = await createSimpleEncryptedDatabase(dbPath);

    // 开始恢复事务
    // 注意：实际恢复需要更复杂的逻辑来处理数据冲突和ID冲突
    // 这里提供基本的恢复框架

    logger.info('Database restore framework ready', {
      backupFile: backupFileName,
      tables: Object.keys(backupData.tables)
    });

    await encryptedDb.close();

    return {
      success: true,
      message: 'Backup restore framework ready',
      backupFile: backupFileName,
      metadata: backupData.metadata
    };

  } catch (error) {
    logger.logError(error, { operation: 'restore_backup', backupFileName });
    throw error;
  }
};

/**
 * 列出所有备份文件
 */
const listBackups = () => {
  try {
    if (!fs.existsSync(backupConfig.backupDir)) {
      return [];
    }

    const backupFiles = fs.readdirSync(backupConfig.backupDir)
      .filter(file => file.endsWith('.backup'))
      .map(file => {
        const filePath = path.join(backupConfig.backupDir, file);
        const stats = fs.statSync(filePath);

        return {
          fileName: file,
          filePath: filePath,
          fileSize: stats.size,
          createdAt: stats.birthtime.toISOString(),
          modifiedAt: stats.mtime.toISOString(),
          type: file.includes('_daily_') ? 'daily' :
                file.includes('_weekly_') ? 'weekly' :
                file.includes('_monthly_') ? 'monthly' : 'manual'
        };
      })
      .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));

    return backupFiles;

  } catch (error) {
    logger.logError(error, { operation: 'list_backups' });
    return [];
  }
};

/**
 * 验证备份文件完整性
 */
const verifyBackup = async (backupFileName) => {
  try {
    const backupFilePath = path.join(backupConfig.backupDir, backupFileName);

    if (!fs.existsSync(backupFilePath)) {
      throw new Error(`Backup file not found: ${backupFileName}`);
    }

    // 计算文件哈希
    const fileContent = fs.readFileSync(backupFilePath);
    const currentHash = crypto.createHash('sha256').update(fileContent).digest('hex');

    // 尝试解密以验证完整性
    const encryptedBackup = JSON.parse(fileContent.toString('utf8'));
    const encryptionKey = getEncryptionKey();
    const backupData = decryptBackupData(encryptedBackup, encryptionKey);

    const verificationResult = {
      fileName: backupFileName,
      isValid: true,
      fileHash: currentHash,
      metadata: backupData.metadata,
      tables: Object.keys(backupData.tables),
      verifiedAt: new Date().toISOString()
    };

    logger.info('Backup verification completed', verificationResult);

    return verificationResult;

  } catch (error) {
    logger.logError(error, { operation: 'verify_backup', backupFileName });
    return {
      fileName: backupFileName,
      isValid: false,
      error: error.message,
      verifiedAt: new Date().toISOString()
    };
  }
};

/**
 * 启动自动备份调度器
 */
const startBackupScheduler = () => {
  logger.info('Starting automatic backup scheduler');

  // 每日备份（凌晨2点）
  setInterval(async () => {
    const now = new Date();
    if (now.getHours() === 2 && now.getMinutes() === 0) {
      try {
        await performBackup('daily');
      } catch (error) {
        logger.error('Scheduled daily backup failed', error);
      }
    }
  }, 60 * 1000); // 每分钟检查一次

  // 每周备份（周日凌晨3点）
  setInterval(async () => {
    const now = new Date();
    if (now.getDay() === 0 && now.getHours() === 3 && now.getMinutes() === 0) {
      try {
        await performBackup('weekly');
      } catch (error) {
        logger.error('Scheduled weekly backup failed', error);
      }
    }
  }, 60 * 1000);

  // 每月备份（每月1号凌晨4点）
  setInterval(async () => {
    const now = new Date();
    if (now.getDate() === 1 && now.getHours() === 4 && now.getMinutes() === 0) {
      try {
        await performBackup('monthly');
      } catch (error) {
        logger.error('Scheduled monthly backup failed', error);
      }
    }
  }, 60 * 1000);

  logger.info('Backup scheduler started successfully');
};

export default {
  performBackup,
  restoreBackup,
  listBackups,
  verifyBackup,
  startBackupScheduler,
  backupConfig
};